/********************************************************************************
* @file    bsp_i2c.c
* @author  jianqiang.xue
* @version V1.1.0
* @date    2023-07-17
* @brief   NULL
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#include "cx32l003_hal.h"

#include "bsp_gpio.h"
#include "bsp_i2c.h"

/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"

/* Private Variables ---------------------------------------------------------*/
#if LS_I2C0_EN
static I2C_HandleTypeDef g_i2c0_handle = { // 定义IIC0信息句柄
    .Instance        = I2C,
    .Init.master     = I2C_MASTER_MODE_ENABLE, // 主机模式使能
    .Init.slave      = I2C_SLAVE_MODE_DISABLE, // 从机模式禁止
    .Mode            = HAL_I2C_MODE_MASTER,    // 主机模式
    .Init.broadack   = I2C_BROAD_ACK_DISABLE,  // 广播地址应答禁止
    .Init.speedclock = LS_I2C0_SPEED_RATE,     // I2C传输速率
    .State           = HAL_I2C_STATE_RESET
};
#endif
/* Private Function Prototypes -----------------------------------------------*/

/**
 * @brief  初始化i2c引脚
 * @param  io: 引脚号
 * @param  arf: 复用值
 */
static inline void io_cfg_as_i2c(uint8_t io, uint8_t arf) {
    if (io == 0 || (io > LS_IO_NUM - 1)) return;
    GPIO_InitTypeDef gpio_init_struct = {
        .Pin             = g_io_cfg[io].io.pin,
        .Mode            = GPIO_MODE_AF,           // 【GPIO端口复用功能】
        .OpenDrain       = GPIO_OPENDRAIN,         // 开漏输出
        .Debounce.Enable = GPIO_DEBOUNCE_DISABLE,  // 禁止输入去抖动
        .SlewRate        = GPIO_SLEW_RATE_HIGH,    // 电压转换速率
        .DrvStrength     = GPIO_DRV_STRENGTH_HIGH, // 驱动强度
        .Pull            = GPIO_PULLUP,            // 上拉
        .Alternate       = arf
    };
    SET_BIT(RCC->HCLKEN, g_io_cfg[io].io.periph);
    HAL_GPIO_Init(g_io_cfg[io].io.port, (GPIO_InitTypeDef*)&gpio_init_struct);
}
/* Public Function Prototypes ------------------------------------------------*/
/**
 * @brief  [初始化] IIC初始化
 * @param  i2c_bus: IIC组号
 * @param  scl: 时钟 引脚号
 * @param  sda: 数据 引脚号
 * @return 0--成功  1--失败
 */
uint8_t bsp_i2c_init(bsp_i2c_bus_t i2c_bus, uint8_t scl, uint8_t sda) {
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        __HAL_RCC_I2C_CLK_ENABLE();
        io_cfg_as_i2c(scl, GPIO_AF4_I2C_SCL);
        io_cfg_as_i2c(sda, GPIO_AF4_I2C_SDA);
        HAL_I2C_Init(&g_i2c0_handle);
        return 0;
#endif
    } else if (i2c_bus == I2C_BUS1) {
#if LS_I2C1_EN
        return 1;
#endif
    }
    return 1;
}

/**
 * @brief  [反初始化] IIC关闭时钟并复位引脚
 * @param  i2c_bus: IIC组号
 */
void bsp_i2c_deinit(bsp_i2c_bus_t i2c_bus) {
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        __HAL_RCC_I2C_CLK_DISABLE();
        HAL_I2C_DeInit(&g_i2c0_handle);
#endif
    }
}

/**
 * @brief  i2c读取一个字节
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  reg_addr: 寄存器地址
 * @param  r_data: 欲发送的数据头指针
 * @retval 0--成功 1--失败
 */
uint8_t bsp_i2c_read_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr,
                          uint8_t reg_addr, uint8_t *r_data) {
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        return HAL_I2C_Master_Receive(&g_i2c0_handle, dev_addr, &reg_addr, 1, r_data, 1);
#endif
    }
    return 1;
}

/**
 * @brief  i2c读取多个字节
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式：(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @param  r_data: rxbuff的头指针
 * @param  r_size: rxbuff的大小
 * @retval 0--成功 1--失败
 */
uint8_t bsp_i2c_read_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr,
                           uint8_t *w_data, uint16_t w_size,
                           uint8_t *r_data, uint16_t r_size) {
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        return HAL_I2C_Master_Receive(&g_i2c0_handle, dev_addr, w_data, w_size, r_data, r_size);
#endif
    }
    return 1;
}

/**
 * @brief  i2c写入一个字节
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  reg_addr: 寄存器地址
 * @param  w_data: 需要写入的字节值
 * @retval 0--成功 1--失败
 */
uint8_t bsp_i2c_write_byte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr,
                           uint8_t reg_addr, uint8_t w_data) {
    uint8_t ret = 0;
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        uint8_t data[2] = {reg_addr, w_data};
        return HAL_I2C_Master_Transmit(&g_i2c0_handle, dev_addr, data, 2);
#endif
    } else {
        ret = 1;
    }
    return ret;
}

/**
 * @brief  i2c写入多个字节
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式：(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败 2--BUSY
 */
uint8_t bsp_i2c_write_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr,
                            uint8_t *w_data, uint16_t w_size) {
    uint8_t ret = 0;
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        ret = HAL_I2C_Master_Transmit(&g_i2c0_handle, dev_addr, w_data, w_size);
#endif
    } else {
        ret = 1;
    }
    return ret;
}

// ---------------------------------散装函数----------------------------------------
/**
 * @brief  i2c写入多个字节且无停止信号(带起始信号和器件地址)
 * @param  i2c_bus: IIC组号
 * @param  dev_addr: 器件地址
 * @param  w_data: txbuff头指针 数据格式：(reg_addr, w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败 2--BUSY
 */
uint8_t bsp_i2c_write_nbyte_nostop(bsp_i2c_bus_t i2c_bus, uint8_t dev_addr,
                                   uint8_t *w_data, uint16_t w_size) {
    uint8_t ret = 0;
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        ret = HAL_I2C_Master_Transmit_NOStop(&g_i2c0_handle, dev_addr, w_data, w_size);
#endif
    } else {
        ret = 1;
    }
    return ret;
}

/**
 * @brief  i2c写入多个字节且无停止信号(不带起始信号和器件地址)
 * @note   必须配合[bsp_i2c_write_nbyte_nostop()]使用
 * @param  i2c_bus: IIC组号
 * @param  w_data: txbuff头指针 数据格式：(w_data, w_data1, ...)
 * @param  w_size: txbuff长度
 * @retval 0--成功 1--失败
 */
uint8_t bsp_i2c_send_nbyte(bsp_i2c_bus_t i2c_bus, uint8_t *w_data, uint16_t w_size) {
    uint8_t ret = 0;
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        uint16_t i = 0;
        uint32_t i2c_flag = 0XFF;
        HAL_I2C_Wait_Flag(&g_i2c0_handle, &i2c_flag);
        while (i < w_size) {
            i2c_flag = 0XFF;
            HAL_I2C_Send_Byte(&g_i2c0_handle, w_data[i]);
            HAL_I2C_Wait_Flag(&g_i2c0_handle, &i2c_flag);
            if (i2c_flag != I2C_FLAG_MASTER_TX_DATA_ACK) { // 0x00000028U
                g_i2c0_handle.State = HAL_I2C_STATE_ERROR;
                g_i2c0_handle.ErrorCode = g_i2c0_handle.PreviousState;
                return 1;
            }
            i++;
        }
#endif
    } else {
        ret = 1;
    }
    return ret;
}

/**
 * @brief  发送一个停止信号
 * @param  i2c_bus: IIC组号
 * @param  state: false--清除中断标志位  true--不清除中断标记位
 * @retval 0--成功 1--失败
 */
uint8_t bsp_i2c_stop(bsp_i2c_bus_t i2c_bus, bool state) {
    uint8_t ret = 0;
    if (i2c_bus == I2C_BUS0) {
#if LS_I2C0_EN
        HAL_I2C_Stop_Config(&g_i2c0_handle, (FunctionalState) true);
#endif
    } else {
        ret = 1;
    }
    return ret;
}
